package easy.trace.plugin.springmvc;

import easy.trace.common.Span;
import easy.trace.core.ICarrier;
import easy.trace.core.context.SqlTraceContext;
import easy.trace.core.context.TraceContext;
import easy.trace.core.dto.ExceptionType;
import easy.trace.core.support.RingBuffer;
import easy.trace.core.support.SpanBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Objects;
import java.util.Optional;

/**
 * @author easy
 */
public class HomePageCarrier implements ICarrier {

    private static final Logger log = LoggerFactory.getLogger(HomePageCarrier.class);
    private SpanBuilder spanBuilder;
    private static ThreadLocal<TraceContext> contextThreadLocal = new ThreadLocal<>();
    private RingBuffer ringBuffer;

    public HomePageCarrier() {
        this.spanBuilder = SpanBuilder.getSpanContextBuilder();
        this.ringBuffer = new RingBuffer();
        this.ringBuffer.start();
    }

    @Override
    public void init(TraceContext context) {
        Optional.ofNullable(context)
                .ifPresent(con -> {
                    if (con.getServiceId() != null) {
                        contextThreadLocal.set(con);
                    }
                });
    }


    @Override
    public void doBeforeHandle() {
        try {
            TraceContext context = contextThreadLocal.get();
            if (Objects.isNull(context)) {
                return;
            }
            if (context.isCalled()) {
                if (context instanceof SqlTraceContext){
                    System.out.println("doBeforeHandle start, sql:  " + ((SqlTraceContext) context).getMySQLEvent());
                }
                System.out.println("doBeforeHandle start " + context.getServiceId());

                Span csSpan = spanBuilder.createCsSpan(
                        context.getServiceId(),
                        context.getMethod(),
                        context.getEventType(),
                        context.address(),
                        context.port());
                spanBuilder.addSrAnnotation(csSpan, context.address(), context.port());
                spanBuilder.setParentSpan(csSpan);
                System.out.println("doBeforeHandle end " + csSpan.getServiceId());
            }
        } catch (Exception e) {
            log.error(e.getLocalizedMessage());
        }
    }

    @Override
    public void doAfterHandle() {
        TraceContext context = contextThreadLocal.get();
        if (Objects.isNull(context)) {
            return;
        }

        try {
            Span currentSpan = spanBuilder.getParentSpan();
            if (Objects.isNull(currentSpan)) {
                return;
            }
            if (context.isCalled()) {
                spanBuilder.addSsAnnotation(currentSpan);
                spanBuilder.addCrAnnotation(
                        currentSpan,
                        context.address(),
                        context.port());
                ringBuffer.add(currentSpan);
            }
        } catch (Exception e) {
            log.error(e.getLocalizedMessage());
        } finally {
            contextThreadLocal.remove();
        }
    }

    @Override
    public void doEncounterException(Exception e, ExceptionType et) {
        final Span parentSpan = spanBuilder.getParentSpan();
        if (Objects.nonNull(parentSpan)) {
            spanBuilder.addExceptionAnnotation(
                    parentSpan,
                    e.getMessage(),
                    et.name());
        }
    }

    @Override
    public void clear() {

    }
}
